# @Time : 2024-11-07 16:05
# @Author : Fioman 
# @Phone : 13149920693
"""
Hough_line 实现步骤
1) 首先,它创建一个二维数组或者累加器(用于保存两个参数的值),并将其初始设置为零.
2) 用r表示行,c表示列
3) 数组的大小取决于你所需要的精度,假设你需要的精度为1度,则需要180列(直线的最大度数为180)
4) 对于r,可能的最大就是是图像的对角线程度.因此,取一个像素精度,行数可以是图像的对角线长度.
"""
import os
import time

import cv2 as cv
import numpy as np

from public_tool import image_helper
from public_tool.data_result import DataResult
from public_tool.image_helper import show_image


def hough_line_simple(imgList) -> DataResult:
    result = DataResult()
    result.data = {
        "mid": None,
        "top": None,
        "bottom": None,
    }
    imgPos = ["mid", "top", "bottom"]
    for index, img in enumerate(imgList):
        cv.destroyAllWindows()
        name = imgPos[index]
        imgColor = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
        edges = cv.Canny(img, 50, 150, apertureSize=3)
        show_image(f"edges_{name}", edges)
        """
        1) rho: 这是霍夫空间中的距离精度，表示每次对距离的采样精度。通常设置为 1，即每个点之间的间距
                    为 1 像素。可以理解为在直线方程中，ρ 轴的分辨率。

        2) theta 控制霍夫空间中角度的分辨率，通常设置为 np.pi / 180，即每次采样 1°（π/180 弧度）。
            这意味着霍夫变换将以 1 度的间隔去检查不同的直线方向。
        
        3) threshold: 阈值，表示最低投票数（累积值）。该值表示需要多少个点投票才能在霍夫空间中形成
                                一条直线。一般来说，较大的 threshold 会导致检测到的直线数量减少，只有更明确的直线会
                                被检测出来。这个阈值决定了返回的直线的强度和明确度。低值会检测到更多的短直线或噪声，
                                较高的值则会减少检测的直线数量，但增加准确性。
        """
        lines = cv.HoughLines(edges, 1, np.pi / 180, 200)
        print("lines个数: {}".format(len(lines)))
        # 返回值是rho,theta,获取直线的K和B,以及直线的中点的Y坐标,选取Y坐标最小的
        lineRes = []  # 保存结果,里面放(k,b,midy)
        for line in lines:
            rho, theta = line[0]
            # theta 是和垂直轴的夹角
            # print(rho, theta)
            if np.sin(theta) != 0:
                k = -np.cos(theta) / np.sin(theta)
                b = rho / np.sin(theta)
                angle = image_helper.get_angle_by_k(k)
                print(f"角度为: {angle}")
                if abs(angle) < 20:
                    # 只要小于20度的角度,因为是水平方向上的
                    startX = 0
                    endX = img.shape[1]
                    midX = int((startX + endX) / 2)
                    startPoint = (startX, int(k * startX + b))
                    endPoint = (endX, int(k * endX + b))
                    midY = int(k * midX + b)
                    lineRes.append((startPoint, endPoint, midY))
        else:
            if len(lineRes) > 0:
                print(f"{name} 找到的全部直线: {lineRes}")
                # 按照Y坐标去排序.top是Y找小的,bottom是Y找大的
                if name == "top":
                    lineFinalFinded = sorted(lineRes, key=lambda x: x[2])[0]
                else:
                    lineFinalFinded = sorted(lineRes, key=lambda x: x[2])[-1]
                leftPoint, rightPoint = lineFinalFinded[:2]
                cv.line(imgColor, leftPoint, rightPoint, image_helper.colorGreen, 2)
                show_image(f"FinalLineFinded_{name}", imgColor)
                result.data[name] = [leftPoint, rightPoint, imgColor]
            else:
                print(f"{name} 没有找到直线")
                result.data[name] = None
    return result


def put_res_to_original_image(image, lineRes, box, offset):
    """
    将小图得到的结果定位到大图上去,并返回其对应的大图上的坐标.
    :param image:
    :param lineRes:
    :param box:
    :param offset:
    :return:
    """


if __name__ == '__main__':
    rootPath = r"F:\raw_2025\4pin_newline"
    image_helper.sizeScale = 4
    image_helper.showState = True
    fileList = image_helper.create_dir_and_get_filenames(rootPath)
    for index, file in enumerate(fileList, start=1):
        print("*" * 10 + f"第 {index} 张图 ({file}) 开始识别" + "*" * 10)
        imagePath = os.path.join(image_helper.fileDir, file)
        imageSrc = cv.imread(imagePath, cv.IMREAD_GRAYSCALE)
        calcStart = time.time()
        boardResult = image_helper.check_totalboard_is_ok(imageSrc)
        if boardResult.state:
            print(f"物料检测通过: {boardResult.info}")
        else:
            print(f"物料检测未通过: {boardResult.info}")
        data = boardResult.data
        box, offset, boardRes, boardResNoAngle, totalboard = (data.box, data.offset, data.boardRes,
                                                              data.boardResNoAngle, data.totalboard)
        if boardResNoAngle is not None:
            cv.imwrite(os.path.join(image_helper.keepTotalBoardResDir, file), boardResNoAngle)
        subImags, subOffsetPix = image_helper.get_sub_images(totalboard)
        lineResult = hough_line_simple(subImags)
        # 将结果定位到大图上去
        imageRes = put_res_to_original_image(imageSrc, lineResult, box, offset)
